#!/usr/bin/env escript

%% Copyright (c) 2020 Facebook, Inc. and its affiliates.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.

%% This file creates ./src/erlt_build_statics.erl,
%% which can be used for accessing the contents of
%% each static file as a string.
%%
%% erlt_build incremental mode uses the following
%% - erlt_build_mk_template is a Makefile template for incremental builds
%%
%% erlt_build_basic_mode.erl uses the following:
%% - defs files, defs.etf files, and beams from ./*.erlt
%%   See ./README.md for details
%%
-module(make_templates).

-mode(compile).

main([OutFilename]) ->
    BuiltInTypes = ["erlang"],
    BuiltInModules = ["t_io", "t_lists"],
    Funs = [get_make_template() | get_built_ins(BuiltInTypes, BuiltInModules)],
    write_module(OutFilename, Funs).

get_make_template() ->
    {mk_template, read_or_error("erlt_build.template.mk")}.

to_name_and_contents(Ext) ->
        fun(Mod) ->
            Basename = Mod ++ Ext,
            FileName = filename:join(["build", Basename]),
            {Basename, read_or_error(FileName)}
        end.

get_built_ins(BuiltInTypes, BuiltInModules) ->
    Ebins = lists:map(to_name_and_contents(".beam"), BuiltInModules),

    TypesMods = BuiltInTypes ++ BuiltInModules,
    Defs = lists:map(to_name_and_contents(".defs"), TypesMods),
    DefsEtfs = lists:map(to_name_and_contents(".defs.etf"), TypesMods),
    [
        {built_in_ebins, Ebins},
        {built_in_defs, Defs ++ DefsEtfs}
    ].


%% @doc for each {FunName, Contents} in Funs, add a function to the output file
%% called <FunName> for getting the contents of <FileName> as a string
write_module(OutFilename, Funs) ->
    ModuleName = filename:basename(OutFilename, ".erl"),
    JoinMap = fun(F) -> string:join(lists:map(F, Funs), "\n") end,
    Erl =
        io_lib:format("%% @generated by erlt/builtins/make_statics.escript DO NOT EDIT~n -module(~s).~n", [ModuleName]) ++
            JoinMap(fun to_export_statement/1) ++
            "\n" ++ 
            JoinMap(fun to_function_def/1),
    ok = file:write_file(OutFilename, Erl).

to_export_statement({Name, _Contents}) ->
    io_lib:format(
        "~n-export([~s/0]).",
        [Name]
    ).

to_function_def({Name, Contents}) ->
    io_lib:format(
        "~n~s() -> ~0p.  ",
        [Name, Contents]
    ).

read_or_error(Path) ->
    case file:read_file(Path) of
        {error, Reason} ->
            io:format(standard_error, "error reading '~p': ~p  ", [
                Path,
                Reason
            ]),
            erlang:error(Reason);
        {ok, Contents} ->
            Contents
    end.
